
export default class DataViewRW {
    private dataView: DataView;
    private offset: number;
    private saveOffset: number;

    constructor(buffer: ArrayBuffer) {
        this.dataView = new DataView(buffer);
        this.offset = 0;
    }

    public reset() {
        this.offset = 0;
    }

    public skip(bytes: number) {
        this.offset += bytes;
    }

    public savePoint() {
        this.saveOffset = this.offset;
    }

    public rollback() {
        this.offset = this.saveOffset;
    }

    public isEnd(): boolean {
        return this.offset >= this.dataView.byteLength;
    }

    public setOffset(offset: number) {
        if (offset >= this.dataView.byteLength) {
            this.offset = this.dataView.byteLength;
        } else {
            this.offset = offset;
        }
    }

    public getUint8() {
        let value = this.dataView.getUint8(this.offset);
        this.offset++;
        return value;
    }

    public getInt8() {
        let value = this.dataView.getUint8(this.offset);
        this.offset++;
        return value;
    }

    public getUint16(endian: boolean = true) {
        let value = this.dataView.getUint16(this.offset, endian);
        this.offset += 2;
        return value;
    }

    public getInt16(endian: boolean = true) {
        let value = this.dataView.getInt16(this.offset, endian);
        this.offset += 2;
        return value;
    }

    public getUint32(endian: boolean = true) {
        let value = this.dataView.getUint32(this.offset, endian);
        this.offset += 4;
        return value;
    }

    public getInt32(endian: boolean = true) {
        let value = this.dataView.getInt32(this.offset, endian);
        this.offset += 4;
        return value;
    }

    public getFloat32(endian: boolean = true) {
        let value = this.dataView.getFloat32(this.offset, endian);
        this.offset += 4;
        return value;
    }
    /** 读取len字节并返回 */
    public getArrayBuffer(length: number) {
        let value = this.dataView.buffer.slice(this.offset, this.offset + length);
        this.offset += length;
        return value;
    }
    /** 读取字符串*/
    public getUniString(namelength: number) {
        let pChars = new Uint16Array(namelength);
        for (let n = 0; n < namelength; n++) {
            pChars[n] = this.getUint16();
            if (pChars[n] == 0x3000) {
                pChars[n] = 32;
            } else if (pChars[n] > 0xFF00 && pChars[n] < 0xFF5F) {
                pChars[n] -= 65248;
            }
        }
        return String.fromCharCode.apply(null, pChars);
    }
    /** 读取len字节并转为字符串 */
    public getGBKString(namelength: number) {
        if (0 == namelength)
            return null;
        let array = new Array();
        for (let i = 0; i < namelength; i++) {
            let byte = this.getUint8();
            array.push(byte);
        }
        return this.byteToString(array);
    }
    /** 字节数组转字符串*/
    private byteToString(arr) {
        if (typeof arr === 'string') {
            return arr;
        }
        let str = '',
            _arr = arr;
        for (let i = 0; i < _arr.length; i++) {
            let one = _arr[i].toString(2),
                v = one.match(/^1+?(?=0)/);
            if (v && one.length == 8) {
                let bytesLength = v[0].length;
                let store = _arr[i].toString(2).slice(7 - bytesLength);
                for (let st = 1; st < bytesLength; st++) {
                    store += _arr[st + i].toString(2).slice(2);
                }
                str += String.fromCharCode(parseInt(store, 2));
                i += bytesLength - 1;
            } else {
                str += String.fromCharCode(_arr[i]);
            }
        }
        return str;
    }

    /** 读取int32*/
    public BufferGetInt(endian: boolean = true) {
        let data_1 = this.dataView.getInt8(this.offset);
        let data_2 = this.dataView.getInt8(this.offset + 1);
        let data_3 = this.dataView.getInt8(this.offset + 2);
        let data_4 = this.dataView.getInt8(this.offset + 3);

        this.offset += 4;
        if (endian) {
            return (data_1 & 0xff) | ((data_2 & 0xff) << 8) | ((data_3 & 0xff) << 16) | ((data_4 & 0xff) << 24);
        } else {
            return (data_1 & 0xff) << 24 | ((data_2 & 0xff) << 16) | ((data_3 & 0xff) << 8) | ((data_4 & 0xff));
        }
    }

    public BufferSetInt(value: number, endian: boolean = true) {
        let data_1 = ((value >> 24) & 0xff);
        let data_2 = ((value >> 16) & 0xff);
        let data_3 = ((value >> 8) & 0xff);
        let data_4 = (value & 0xff);
        if (endian) {
            this.dataView.setInt8(this.offset, data_4);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_3);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_2);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_1);
            this.offset += 1;
        } else {
            this.dataView.setInt8(this.offset, data_1);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_2);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_3);
            this.offset += 1;
            this.dataView.setInt8(this.offset, data_4);
            this.offset += 1;
        }

    }

    public BufferGetShort() {
        let data_1 = this.dataView.getInt8(this.offset);
        let data_2 = this.dataView.getInt8(this.offset + 1);
        this.offset += 2;
        return ((data_1 & 0xff)) | ((data_2 & 0xff) << 8);
    }
    /** 读取int64*/
    public BufferGetLong() {
        let data_1 = this.dataView.getInt8(this.offset);
        let data_2 = this.dataView.getInt8(this.offset + 1);
        let data_3 = this.dataView.getInt8(this.offset + 2);
        let data_4 = this.dataView.getInt8(this.offset + 3);
        let data_5 = this.dataView.getInt8(this.offset + 4);
        let data_6 = this.dataView.getInt8(this.offset + 5);
        let data_7 = this.dataView.getInt8(this.offset + 6);
        let data_8 = this.dataView.getInt8(this.offset + 7);

        this.offset += 8;
        return (data_1 & 0x00ff) | ((data_2 & 0x00ff) << 8) | ((data_3 & 0x00ff) << 16) | ((data_4 & 0x00ff) << 24) |
            ((data_5 & 0x00ff) << 32) | ((data_6 & 0x00ff) << 40) | ((data_7 & 0x00ff) << 48) | ((data_8 & 0x00ff) << 64);
    }

    public setInt8(value: number) {
        this.dataView.setInt8(this.offset, value);
        this.offset++;
    }

    public setUint8(value: number) {
        this.dataView.setUint8(this.offset, value);
        this.offset++;
    }

    public setInt16(value: number, endian: boolean) {
        this.dataView.setInt16(this.offset, value, endian);
        this.offset += 2;
    }

    public setUint16(value: number, endian: boolean) {
        this.dataView.setUint16(this.offset, value, endian);
        this.offset += 2;
    }

    public setInt32(value: number, endian: boolean) {
        this.dataView.setInt32(this.offset, value, endian);
        this.offset += 4;
    }

    public setUint32(value: number, endian: boolean) {
        this.dataView.setUint32(this.offset, value, endian);
        this.offset += 4;
    }

    public setFloat32(value: number, endian: boolean) {
        this.dataView.setFloat32(this.offset, value, endian);
        this.offset += 4;
    }

    public setFloat64(value: number, endian: boolean) {
        this.dataView.setFloat64(this.offset, value, endian);
        this.offset += 8;
    }


}